﻿using LibNiconico.NiconicoApi;
using LibNiconico.NiconicoApi.Lives;
using LibNiconico.NiconicoApi.Lives.Comments;
using LibNiconico.NiconicoApi.PlayerStatus;
using LibNiconico.NiconicoApi.Utils;
using NicoView.Model.Service.Broadcast;
using NicoView.Model.Service.Comments;
using NicoView.Model.Service.Events;
using NicoView.Model.Service.Results;
using NicoView.Model.Timer;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NicoView.Model.Service.Lives
{
    public sealed class NicoLiveService:NicoServiceBase
    {




        internal NicoLiveService( NicoPlayerStatus playerStatus, INicoLiveCommentClient commentClient, NicoViewApplication baseApplication)
            : base(baseApplication)
        {


            LiveServiceInfo = new NicoLiveServiceInfo(playerStatus);
            this.MainCommentClient = new NicoLiveCommentClient(this, commentClient);

            this.MainCommentClient.Received += mainCommentClient_Received;

            this.MainCommentClient.ThreadReceived += mainCommentClient_ThreadReceived;

            this.MainCommentClient.HeartBeatReceived += mainCommentClient_HeartBeatReceived;

            this.MainCommentClient.Closed += mainCommentClient_Closed;

            
        }

        void mainCommentClient_Closed(NicoLiveCommentCloseEventArgs args)
        {
            if (this.Timer.IsEnabled)
            {
                this.Timer.Stop();
            }
            if (args.Exception != null)
            {
                this.BaseApplication.OnNotifyWaning(new NicoWarningEventArgs(args.Exception, args.Exception.Message));
            }
        }

        

        public override void Dispose()
        {
            if (this.Timer.IsEnabled)
            {
                this.Timer.Stop();
            }
            base.Dispose();
        }


        

        private void mainCommentClient_HeartBeatReceived(NicoLiveHeartBeatReceivedEventArgs args)
        {
            this.elapsed(args.Time);

            this.WatchCount = args.WatchCount;
            this.CommentCount = args.CommentCount;
        }

        private void mainCommentClient_ThreadReceived(NicoCommentThreadEventArgs args)
        {
            this.elapsed(args.Time);
        }

        private void mainCommentClient_Received(NicoCommentReceiveEventArgs args)
        {
            var lastComments = from comment in args.Comments
                               where comment.IsNew
                              orderby comment.Date ascending
                              select comment;
            if(lastComments.Count() > 0)
            {
                this.elapsed(lastComments.Last().Date);
            }
        }



        public NicoLiveCommentClient MainCommentClient { get; private set; }

        public NicoLiveServiceInfo LiveServiceInfo { get; private set; }




        public async Task CommentServerConnectAsync()
        {

            await MainCommentClient.ConnectAsync();

        }
        
        public override INicoCommentClient CommentClient
        {
            get { return MainCommentClient; }
        }

        public override INicoServiceInfo ServiceInfo
        {
            get { return LiveServiceInfo; }
        }


        private void elapsed(DateTime now)
        {
            this.ServiceElapsedTime = now - this.ServiceInfo.StartTime;
            this.UpdateActiveWatchCount();
        }

        internal override event NicoCommentGetUserRequestHandler UserRequest
        {
            add
            {
                MainCommentClient.UserInfoRequest += value;
            }
            remove
            {
                MainCommentClient.UserInfoRequest -= value;
            }
        }

        public override NicoServiceType ServiceType
        {
            get { return NicoServiceType.Live; }
        }

        



        protected override async Task<IResult> OnEndTimeActionAsync()
        {


                var playerStatus = await this.BaseApplication.Instance.GetPlayerStatusAsync(this.ServiceInfo.Id);
                
                
                if (playerStatus.Error.Code == NicoErrorCode.Closed)
                {
                    if (this.LiveServiceInfo.IsOwner && this.BaseApplication.Property.AutoCreateNextBroadcast && 
                        this.BaseApplication.Instance.BroadcastingController != null &&
                        this.ServiceInfo.Id == this.BaseApplication.Instance.BroadcastingController.BroadcastingLiveId
                        )
                    {
                        await this.BaseApplication.Instance.AutoStartNextBroadcastAsync();
                    }


                    this.Timer.Stop();
                    return new Result(true);
                }
                else if (playerStatus.Succeed)
                {
                    if (playerStatus.PlayerStatus.Stream.EndTime > this.LiveServiceInfo.EndTime)
                    {
                        this.LiveServiceInfo.SetPlayerStatus(playerStatus.PlayerStatus);
                    }

                        
                    return new Result(true);
                }


                else
                {
                    this.Timer.Stop();
                    return new Result(false, playerStatus.Error.Description);
                }
               
                
            

        }

        
    }
}
